package com.qnvip.sbd.mybatis.sqlprovider;

import com.qnvip.sbd.mybatis.exception.ParameterNotFoundException;
import com.qnvip.sbd.mybatis.exception.SqlNoWhereConditionException;
import com.qnvip.sbd.mybatis.util.Field;
import com.qnvip.sbd.mybatis.util.SelectMap;
import com.qnvip.sbd.mybatis.util.UpdateMap;
import com.qnvip.sbd.util.PropertiesUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.jdbc.SqlBuilder;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

public class SqlProvider {
	
	public String select(Map<String, Object> parameter)
			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		String otherCondition = (String) parameter.get("otherCondition");
		String targetColumns = (String) parameter.get("targetColumns");
		Object object = parameter.get("condition");
		if (object == null) {
			new ParameterNotFoundException(
					"Require an 'object' named key to return object value as the target  from table.");
		}
		if (targetColumns == null) {
			targetColumns = "*";
		}
		String table = SqlProviderHelper.getTable(object);
		SqlConditionProvider sqlConditionProvider = new SqlConditionProvider(object);
		if (otherCondition == null) {
			otherCondition = "";
		} else {
			otherCondition = otherCondition.trim();
			if (!(otherCondition.toLowerCase().startsWith("limit")
					|| otherCondition.toLowerCase().startsWith("order by"))) {
				otherCondition = " and " + otherCondition;
			}
		}
		String condition = sqlConditionProvider.getCondition();
		String clause = "select " + targetColumns + " from " + table + " where 0=0 " + condition + otherCondition;
		printSql(clause);
		return clause;
	}
	
	public String count(Map<String, Object> parameter) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Object object = parameter.get("condition");
		String otherCondition = (String) parameter.get("otherCondition");
		if (object == null) {
			new ParameterNotFoundException(
					"Require an 'object' named key to return object value as the target select from table.");
		}
		String table = SqlProviderHelper.getTable(object);
		SqlConditionProvider sqlConditionProvider = new SqlConditionProvider(object);
		StringBuilder sql = new StringBuilder();
		sql.append("select count(*) from ").append(table).append(" where 0=0");
		String condition = sqlConditionProvider.getCondition();
		sql.append(condition);
		if (StringUtils.isNotEmpty(otherCondition)) {
			sql.append(" and ").append(otherCondition);
		}
		printSql(sql.toString());
		return sql.toString();
	}

	public String delete(Map<String, Object> parameter)
			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Object object = parameter.get("condition");
		if (object == null) {
			new ParameterNotFoundException("Require an 'object' to delete.");
		}
		String table = SqlProviderHelper.getTable(object);
		SqlConditionProvider sqlConditionProvider = new SqlConditionProvider(object);
		String whereCondition = sqlConditionProvider.getCondition();
		if (whereCondition == null || whereCondition.length() == 0) {
			throw new SqlNoWhereConditionException("删除操作没有where条件");
		}
		String clause = "delete from " + table + " where 0=0 " + whereCondition;
		printSql(clause);
		return clause;
	}
	
	public String updateByUpdateMap(UpdateMap updateMap) {
		SqlBuilder.BEGIN();
		SqlBuilder.UPDATE(updateMap.getTable());
		for (Field field : updateMap.getFields()) {
			String val = field.getValue();
			if (field.isColumn()) {
				SqlBuilder.SET(field.getName() + field.getOperator() + val);
			} else {
				if (val == null) {
					SqlBuilder.SET(field.getName() + field.getOperator() + "null");
				} else {
					SqlBuilder.SET(field.getName() + field.getOperator() + "'" + val + "'");
				}
			}
		}
		for (Field field : updateMap.getWhere()) {
			if ("in".equals(field.getOperator().toLowerCase())) {
				SqlBuilder.WHERE(field.getName() + " in (" + field.getValue() + ")");
			} else {
				SqlBuilder.WHERE(field.getName() + field.getOperator() + "'" + field.getValue() + "'");
			}
		}
		String sql = SqlBuilder.SQL();
		if (StringUtils.indexOfIgnoreCase(sql, "where") < 0) {
			throw new SqlNoWhereConditionException("更新操作没有where条件");
		}
		printSql(sql);
		return sql;
	}

	public String insert(Object object) throws IllegalAccessException, IllegalArgumentException,
			InvocationTargetException, IOException {
		if (object == null) {
			new ParameterNotFoundException("Require an 'object' to insert.");
		}
		SqlInsertProvider sqlInsertProvider = new SqlInsertProvider(object);
		String clause = sqlInsertProvider.getInsertStatement();
		printSql(clause);
		return clause;
	}
	
	
	public String sum(Map<String, Object> parameter) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Object object = parameter.get("condition");
		String targetColumn = (String) parameter.get("targetColumn");
		String otherCondition = (String) parameter.get("otherCondition");
		if (object == null) {
			new ParameterNotFoundException(
					"Require an 'object' named key to return object value as the target select from table.");
		}
		String table = SqlProviderHelper.getTable(object);
		SqlConditionProvider sqlConditionProvider = new SqlConditionProvider(object);
		StringBuilder sql = new StringBuilder();
		sql.append("select ifnull(sum(").append(targetColumn).append("), 0) from ").append(table).append(" where 0=0");
		String condition = sqlConditionProvider.getCondition();
		sql.append(condition);
		if (StringUtils.isNotEmpty(otherCondition)) {
			sql.append(" and ").append(otherCondition);
		}
		printSql(sql.toString());
		return sql.toString();
	}
	
	public String selectWithSelectMap(SelectMap selectMap) {
		String table = selectMap.getTable();
		StringBuilder sql = new StringBuilder();
		sql.append("select ").append(selectMap.getTargetColumn()).append(" from ").append(table);
		if (StringUtils.isNotEmpty(selectMap.getJoin())) {
			sql.append(" ").append(selectMap.getJoin());
		}
		if (selectMap.getJoins().size() > 0) {
			for (String str : selectMap.getJoins()) {
				sql.append(" ").append(str);
			}
		}
		sql.append(" where 0=0 ");
		for (Field field : selectMap.getWhere()) {
			if ("in".equals(field.getOperator().toLowerCase())) {
				sql.append(" and ").append(field.getName() + " in (" + field.getValue() + ")");
			} else {
			    if (field.isColumn()) {
			        sql.append(" and ").append(field.getName() + field.getValue());
			    } else {
			        sql.append(" and ").append(field.getName() + field.getOperator() + "'" + field.getValue() + "'");
			    }
			}
		}
		if (StringUtils.isNotEmpty(selectMap.getGorupBy())) {
			sql.append(" ").append(selectMap.getGorupBy());
		}
		if (StringUtils.isNotEmpty(selectMap.getOrderBy())) {
			sql.append(" ").append(selectMap.getOrderBy());
		}
		if (StringUtils.isNotEmpty(selectMap.getHaving())) {
			sql.append(" ").append(selectMap.getHaving());
		}
		printSql(sql.toString());
		return sql.toString();
	}
	
	private void printSql(String sql) {
		if (PropertiesUtil.getBoolean("sql.debug")) {
			System.out.println(sql);
		}
	}

}
